/**
 *
 */
package soa.security.mgr.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Service;
import soa.security.Constants;
import soa.security.domain.*;
import soa.security.mgr.service.*;
import soa.security.mgr.service.base.BaseMgrService;
import soa.security.web.LdapAuthenticationFilter;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Cre.Gu
 */
@Service
public class TreeMgrServiceImpl implements TreeMgrService {
    protected final org.slf4j.Logger log = org.slf4j.LoggerFactory
            .getLogger(this.getClass());

    @Resource(name = "baseMgrServiceImpl")
    private BaseMgrService baseMgrService;
    @Resource
    private RegionMgrService regionMgrService;
    @Resource
    private OrganizationMgrService organizationMgrService;
    @Resource
    private DepartmentMgrService departmentMgrService;
    @Resource
    private PersonMgrService personMgrService;
    @Resource
    private PositionMgrService positionMgrService;
    @Resource
    private GroupMgrService groupMgrService;
    @Resource
    private AccountMgrService accountMgrService;


    @Override
    public List<LdapTree> regionTree() {
        String rootDn = Region.root().buildDn().toString();
        return doRegionTree(rootDn, null, false, false);
    }

    @Override
    public List<LdapTree> organizationTree() {
        return organizationTree(false);
    }

    @Override
    public List<LdapTree> organizationRsTree() {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            results.addAll(doRegionTree(Region.root().buildDn().toString(),
                    null, true, false));

        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> departmentTree() {
        return organizationTree(true);
    }

    List<LdapTree> organizationTree(boolean addDepartment) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {

            if (SecurityUtils.getSubject().isAuthenticated()
                    && !gainAccountFromSession().isSupered()
                    && gainFromSession() != null) {
                Organization organization = gainFromSession();
                results.addAll(oneOrgTree(organization, addDepartment));
            } else
                results.addAll(doRegionTree(Region.root().buildDn().toString(),
                        null, true, addDepartment));

        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    protected List<LdapTree> doRegionTree(String parentDn, Region parent,
                                          boolean addOrganization, boolean addDepartment) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        List<Region> list = regionMgrService.allRegions(parentDn);
        try {
            for (Region region : list) {
                results.add(wrapRegion(region, parent));

                if (addOrganization)
                    results.addAll(doOrganizationTree(
                            region.getDn().toString(), region, null,
                            addDepartment));
                results.addAll(doRegionTree(region.getDn().toString(), region,
                        addOrganization, addDepartment));
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    protected List<LdapTree> doOrganizationTree(String parentDn, Region region,
                                                Organization parent, boolean addDepartment) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        List<Organization> list = organizationMgrService
                .allOrganizations(parentDn);

        for (Organization or : list) {
            results.add(wrapOrganization(or, region, parent));

            if (addDepartment)
                results.addAll(doDepartmentTree(or));
            results.addAll(doOrganizationTree(or.getDn().toString(), null, or,
                    addDepartment));
        }
        return results;
    }

    protected List<LdapTree> doDepartmentTree(Organization organization) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        String organizationId = organization.getBid();

        OrganizationUnit unit = baseMgrService.gainOrganizationUnit(
                organizationId, Constants.DEPARTMENT);
        if (unit == null)
            return results;

        String baseDn = unit.getDn().toString();
        List<Department> list = departmentMgrService
                .allDepartments(organizationId);

        for (Department de : list) {
            results.add(wrapDepartment(de, baseDn, organization));
        }
        return results;

    }

    protected LdapTree wrapRegion(Region region, Region parent) {
        LdapTree ldapTree = new LdapTree(region.getDn().toString(),
                region.getDc(), region.getName(), Region.class);
        ldapTree.setRegionLevel("rl-" + region.getRegionLevel());
        ldapTree.setRegion(parent);
        return ldapTree;
    }

    protected LdapTree wrapOrganization(Organization or, Region region,
                                        Organization parent) {
        LdapTree ldapTree = new LdapTree(or.getDn().toString(), or.getBid(),
                or.getName(), Organization.class);

        ldapTree.setRegion(region);
        ldapTree.setOrganization(parent);
        return ldapTree;
    }

    protected LdapTree wrapDepartment(Department de, String baseDn,
                                      Organization organization) {
        LdapTree ldapTree = new LdapTree(de.getDn().toString(), de.getBid(),
                de.getName(), Department.class);

        if (StringUtils.isBlank(de.getParentBid())) {
            ldapTree.setOrganization(organization);
        } else {
            ldapTree.setDepartment(departmentMgrService.findByBid(baseDn,
                    de.getParentBid()));
        }
        ldapTree.setOrganizationId(organization.getBid());
        return ldapTree;
    }

    protected LdapTree wrapAccount(Account account, String baseDn,
                                   Organization organization) {
        LdapTree ldapTree = new LdapTree(account.getDn().toString(), account.getBid(),
                account.getBid(), Account.class);
        ldapTree.setOrganization(organization);
        ldapTree.setOrganizationId(organization.getBid());
        return ldapTree;
    }

    protected LdapTree wrapPerson(Person de, Organization organization) {
        LdapTree ldapTree = new LdapTree(de.getDn().toString(), de.getUid(),
                de.getName(), Person.class);
        ldapTree.setOrganization(organization);

        return ldapTree;
    }

    protected LdapTree wrapPosition(Position de, Organization organization) {
        LdapTree ldapTree = new LdapTree(de.getDn().toString(), de.getBid(),
                de.getName(), Position.class);

        ldapTree.setOrganization(organization);
        return ldapTree;
    }

    protected LdapTree wrapGroup(Group de, Organization organization) {
        LdapTree ldapTree = new LdapTree(de.getDn().toString(), de.getBid(),
                de.getName(), Group.class);

        ldapTree.setOrganization(organization);
        return ldapTree;
    }

    protected LdapTree wrapRole(Role de, Organization organization) {
        LdapTree ldapTree = new LdapTree(de.getDn().toString(), de.getBid(),
                de.getName(), Role.class);

        ldapTree.setOrganization(organization);
        return ldapTree;
    }

    private Organization gainFromSession() {
        return (Organization) SecurityUtils
                .getSubject()
                .getSession()
                .getAttribute(LdapAuthenticationFilter.SESSION_ORGANIZATION_KEY);
    }

    private Account gainAccountFromSession() {
        return (Account) SecurityUtils.getSubject().getSession()
                .getAttribute(LdapAuthenticationFilter.SESSION_ACCOUNT_KEY);
    }

    @Override
    public List<LdapTree> personInOneOrgTree(String organizationId) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            Organization organization = baseMgrService
                    .findOrganization(organizationId);
            List<Person> list = personMgrService.allPersons(organization
                    .getBid());

            if (list.size() > 0)
                results.add(wrapOrganization(organization, null, null));

            for (Person de : list) {
                results.add(wrapPerson(de, organization));
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> deptInOneOrgTree(String organizationId) {
        return deptInOneOrgTree(organizationId, null);
    }

    @Override
    public List<LdapTree> deptInOneOrgTree(String organizationId,
                                           String departmentId) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            Organization organization = baseMgrService
                    .findOrganization(organizationId);

            OrganizationUnit unit = baseMgrService.gainOrganizationUnit(
                    organizationId, Constants.DEPARTMENT);
            String baseDn = unit.getDn().toString();

            List<Department> list = departmentMgrService
                    .allDepartments(organizationId);
            if (list.size() > 0)
                results.add(wrapOrganization(organization, null, null));

            String filterId = departmentId;
            for (Department de : list) {
                if (de.getBid().equals(filterId))
                    continue;
                results.add(wrapDepartment(de, baseDn, organization));
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> accountInOneOrgTree(String organizationId) {
        return accountInOneOrgTree(organizationId, null);
    }

    @Override
    public List<LdapTree> accountInOneOrgTree(String organizationId,
                                              String accountId) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            Organization organization = baseMgrService
                    .findOrganization(organizationId);

            OrganizationUnit unit = baseMgrService.gainOrganizationUnit(
                    organizationId, Constants.ACCOUNT);
            String baseDn = unit.getDn().toString();

            List<Account> list = accountMgrService.allAccounts(organizationId);
            if (list.size() > 0)
                results.add(wrapOrganization(organization, null, null));

            String filterId = accountId;
            for (Account de : list) {
                if (de.getBid().equals(filterId))
                    continue;
                results.add(wrapAccount(de, baseDn, organization));
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> deptInOneOrgCheckTree(String organizationId,
                                                List<Department> checked, String departmentId) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            results = deptInOneOrgTree(organizationId);
            filteOrganization(results, organizationId);

            for (LdapTree lt : results) {
                if (lt.getBid().equals(departmentId)) {
                    lt.setChecked(true);
                }
                for (Department per : checked) {
                    if (lt.getId().equals(per.getDn().toString())) {
                        lt.setChecked(true);
                        break;
                    }
                }
                lt.setOrganization(null);
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> accountInOneOrgCheckTree(String organizationId,
                                                   List<Account> checked) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            results = accountInOneOrgTree(organizationId);
            filteOrganization(results, organizationId);

            for (LdapTree lt : results) {
                for (Account per : checked) {
                    if (lt.getId().equals(per.getDn().toString())) {
                        lt.setChecked(true);
                        break;
                    }
                }
                lt.setOrganization(null);
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> adminTree(String dn, String bid, String text) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            LdapTree ldapTree = new LdapTree(dn, bid, text);
            ldapTree.setChecked(true);
            results.add(ldapTree);
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    private void filteOrganization(List<LdapTree> list, String organizationId) {
        Iterator<LdapTree> iter = list.iterator();
        while (iter.hasNext()) {

            LdapTree lt = iter.next();
            if (lt.getBid().equals(organizationId)) {
                iter.remove();
            }
        }
    }

    @Override
    public List<LdapTree> personInOneOrgCheckTree(String organizationId,
                                                  List<Person> checked) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            results = personInOneOrgTree(organizationId);
            filteOrganization(results, organizationId);

            for (LdapTree lt : results) {
                for (Person per : checked) {

                    if (lt.getId().equals(per.getDn().toString())) {
                        lt.setChecked(true);
                        break;
                    }
                }
                lt.setOrganization(null);
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> subGroupInOneOrgCheckTree(String organizationId,
                                                    String filterId, List<Group> checked) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            results = groupInOneOrgTree(organizationId);
            filteOrganization(results, organizationId);

            List<Group> parents = groupMgrService.findParents(organizationId,
                    filterId, true);
            if (StringUtils.isNotBlank(filterId))
                parents.add(groupMgrService.findByDn(filterId));

            // 过滤父组+自身
            Iterator<LdapTree> iter = results.iterator();
            while (iter.hasNext()) {
                LdapTree lt = iter.next();

                for (Group group : parents) {
                    if (lt.getBid().equals(group.getBid())) {
                        iter.remove();
                        break;
                    }
                }
            }

            for (LdapTree lt : results) {
                for (Group per : checked) {

                    if (lt.getId().equals(per.getDn().toString())) {
                        lt.setChecked(true);
                        break;
                    }
                }
                lt.setOrganization(null);
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    protected List<LdapTree> groupInOneOrgTree(String organizationId) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            Organization organization = baseMgrService
                    .findOrganization(organizationId);
            List<Group> list = groupMgrService.allGroups(organization.getBid());

            if (list.size() > 0)
                results.add(wrapOrganization(organization, null, null));

            for (Group group : list) {
                results.add(wrapGroup(group, organization));
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> groupInOneOrgCheckTree(String organizationId,
                                                 List<Group> checked) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            results = groupInOneOrgTree(organizationId);
            filteOrganization(results, organizationId);

            for (LdapTree lt : results) {
                for (Group per : checked) {

                    if (lt.getId().equals(per.getDn().toString())) {
                        lt.setChecked(true);
                        break;
                    }
                }
                lt.setOrganization(null);
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> positionInOneOrgCheckTree(String organizationId,
                                                    List<Position> checked) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            results = positionInOneOrgTree(organizationId);
            filteOrganization(results, organizationId);

            for (LdapTree lt : results) {
                for (Position per : checked) {

                    if (lt.getId().equals(per.getDn().toString())) {
                        lt.setChecked(true);
                        break;
                    }
                }
                lt.setOrganization(null);
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    protected List<LdapTree> positionInOneOrgTree(String organizationId) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            Organization organization = baseMgrService
                    .findOrganization(organizationId);
            List<Position> list = positionMgrService.allPositions(organization
                    .getBid());

            if (list.size() > 0)
                results.add(wrapOrganization(organization, null, null));

            for (Position group : list) {
                results.add(wrapPosition(group, organization));
            }
        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }

    @Override
    public List<LdapTree> oneOrgTree(String organizationId) {
        Organization organization = baseMgrService
                .findOrganization(organizationId);
        return oneOrgTree(organization, false);
    }

    public List<LdapTree> oneOrgTree(Organization organization,
                                     boolean addDepartment) {
        List<LdapTree> results = new ArrayList<LdapTree>();
        try {
            results.add(wrapOrganization(organization, null, null));
            if (addDepartment)
                results.addAll(doDepartmentTree(organization));

            results.addAll(doOrganizationTree(organization.getDn().toString(),
                    null, organization, addDepartment));

        } catch (Exception e) {
            log.debug("报错", e);
        }
        return results;
    }
}
